
#include <iostream>
#include <queue>
#include <pthread.h>

constexpr int defaultcapacity = 10;
constexpr int defaulthighlevel = 6;
constexpr int defaultlowlevel = 4;

// 阻塞队列
template<class T>
class BlockQueue
{
public:
    BlockQueue(const int capacity = defaultcapacity , const int highlevel = defaulthighlevel , const int lowlevel = defaultlowlevel)
        :capacity_(capacity), highlevel_(highlevel)  ,lowlevel_(lowlevel)
    {
        pthread_mutex_init(&mutex, nullptr);
        pthread_cond_init(&p_cond , nullptr);
        pthread_cond_init(&c_cond , nullptr);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&p_cond);
        pthread_cond_destroy(&c_cond);
    }


    // 向队列中添加元素
    void push(const T& data)
    {
        // 要向队列中添加了元素,先加锁
        pthread_mutex_lock(&mutex);
        while(q.size() == capacity_)       // 如果队列已经满了，不能再继续先队列中加入；使用循环是为了防止消费者被误唤醒
            pthread_cond_wait(&p_cond , &mutex);

        // 添加数据
        q.push(data);

        // 通知消费者使用数据
        if(q.size() >= highlevel_) 
            pthread_cond_broadcast(&c_cond);
        pthread_mutex_unlock(&mutex);       // 还锁
    }

    // 从队列中取出元素
    T pop()
    {
        // 先加锁
        pthread_mutex_lock(&mutex);
        while(q.size() < 1)                   // 队列为空,等待
            pthread_cond_wait(&c_cond, &mutex);
        
        // 取出元素
        T ret = q.front();
        q.pop();

        if(q.size() <= lowlevel_)
            pthread_cond_broadcast(&p_cond);

        pthread_mutex_unlock(&mutex);
        return ret;
    }

private:
    std::queue<T> q;
    pthread_mutex_t mutex;    // 互斥锁
    pthread_cond_t p_cond;    // 生产者的条件变量
    pthread_cond_t c_cond;    // 消费者的条件变量
    int capacity_;
    int highlevel_;
    int lowlevel_;
};

